var FMFPFacilityUtils = function () {
    
   /*
    * Function to retrieve all Buildings and their info
    * @result FMFPOperationResult.result {JSON} returns a JSON with info regarding all buildings
    */
    function getBuildings(){
        return _getData('building');
    }
         
   /*
    * Function to retrieve all checkout information for a specific Facility
    * @param facility_sys_id {string} sys_id of the Facility
    * @result FMFPOperationResult.result {JSON} contains the info regarding the active version of a Facility
    */
    function getFacilityActiveVersionInfo(facility_sys_id) {
        var json = {
            username:undefined,
            startdate:undefined,
            deadlinedate:undefined
        };
        //Get facility active version
        var grVersions = new GlideRecord(FMConstants.Table.VERSION);
        grVersions.addQuery("record", facility_sys_id);
        grVersions.addQuery("status","IN", "active , draft");
        grVersions.orderBy('status');
        grVersions.setLimit(1);
        grVersions.query();

        if (grVersions.next()){
            var grUser = new GlideRecord('sys_user');
            grUser.addQuery('sys_id',grVersions.getValue("checked_out_by"));
            grUser.query();
            if (grUser.next()){
                json.username = grUser.getValue("user_name");
                json.startdate = grVersions.getValue("checked_out_date");
                json.deadlinedate = grVersions.getValue("checkout_deadline");
                return new FMFPOperationResult(true,'Operation successful.',json);
            }
        }
        return new FMFPOperationResult(false,'Operation unsuccessful.',json);
    }
    
   /*
    * Used to retrieve DWG on read-only mode, will always return the Active version
    * @param facility_sys_id {string} sys_id of the Facility
    * @return FMFPOperationResult.result {string} sys_id of DWG record on sys_attachment table
    */
    function getFloorDWG(facility_sys_id) {
        var grVersions = new GlideRecord(FMConstants.Table.VERSION);
        grVersions.addQuery("record", facility_sys_id);
        grVersions.addQuery("status", "active");
        grVersions.orderByDesc('status');
        grVersions.setLimit(1);
        grVersions.query();
        
        var versionSysId = "";
        
        if (grVersions.next()) {
            versionSysId =  grVersions.getValue("sys_id");
            return _getVersionDWG(versionSysId);
        }
        
        return new FMFPOperationResult(false,'Operation unsuccessful.',undefined);
    }
    
   /*
    * Function to retrieve a specific Building, it's respective Floors and their info
    * @param sys_id {string} sys_id of the Building
    * @result FMFPOperationResult.result {JSON} returns a JSON with info regarding the Building info and all it's Floors
    */
    function getFloors(sys_id) {
        return _getData('floor', sys_id);
    }
    
   /*
    * Function to retrieve a specific Floor, it's respective Rooms and their info
    * @param sys_id {string} sys_id of the Floor
    * @result FMFPOperationResult.result {JSON} returns a JSON with info regarding the Floor info and all it's Rooms
    */
    function getRooms(sys_id) {
        return _getData('room', sys_id);
    }
    
   /*
    * Function to retrieve information regarding a specific facility, depending on it's type
    * @param facility_sys_id {string} sys_id of the Facility
    * @param facility {string} string with the name of the Facility table
    * @result FMFPOperationResult.result {JSON} contains the info regarding the Facility
    */
    function getFacilityDetails(facility_sys_id, facility) {
        var facilityJSON = {};
        var grFacility = new GlideRecord("x_lsmcb_fm_" + facility);
        grFacility.addQuery('sys_id',facility_sys_id);
        grFacility.query();
        if (grFacility.next()){
            switch(facility) {
                case 'floor':
                    facilityJSON.Id = grFacility.getValue('id');
                    facilityJSON.Name = grFacility.getValue('name');
                    facilityJSON.Rooms = getRooms(facility_sys_id).result;
                    facilityJSON.DWG_SysID = getFloorDWG(facility_sys_id).result;
                    facilityJSON.Checkout = getFacilityActiveVersionInfo(facility_sys_id).result;
                    return new FMFPOperationResult(true,'Operation successful.',facilityJSON);
                case 'building':
                    facilityJSON.Id = grFacility.getValue('id');
                    facilityJSON.Name = grFacility.getValue('name');
                    facilityJSON.Floors = getFloors(facility_sys_id).result;
                    facilityJSON.Sys_Id = facility_sys_id;
                    return new FMFPOperationResult(true,'Operation successful.',facilityJSON);
                default:
                    break;
            }
        }
        return new FMFPOperationResult(false,'Operation unsuccessful.',facilityJSON);
    }
    
   /*
    * Function to generate facilities
    * @param versionSysID {string} Version sys_id
    * @param isNewFloor {boolean} indicates whether we want to generate other building and floor or not 
    * @param building {string} floor ID field
    * @param floor {string} floor ID field
    * @result FMFPOperationResult
    */
    function generateFacilities(versionSysID, isNewFloor, building, floor) {
        // Check the Autocad Property 'autocad_autocreate_facilities'
        if (gs.getProperty(FMConstants.Property.AUTOCAD_AUTOCREATE_FACILITIES) == 'false')
            return FMFPOperationResult(true, "Facility generation is disabled.");

        if (typeof building != 'undefined' && typeof floor != 'undefined') {

            var floorID = building + '.' + floor;
            var grFloor = new GlideRecord(FMConstants.Table.FLOOR);

            var grFloorVersion = new GlideRecord(FMConstants.Table.VERSION);
            grFloorVersion.get(versionSysID);

            var buildingSysID = '';
            var floorSysID = '';

            //Create new floor
            if (isNewFloor) {

                //Check if a floor with this ID already exists
                var grFloorCheck = new GlideRecord(FMConstants.Table.FLOOR);
                grFloorCheck.addQuery('id', floorID);
                grFloorCheck.query();
                if (grFloorCheck.hasNext())
                    return FMFPOperationResult(false, "The Floor ID already exists.");

                var grBuilding = new GlideRecord(FMConstants.Table.BUILDING);
                grBuilding.addQuery('id', building);
                grBuilding.query();

                if (grBuilding.hasNext()) {
                    buildingSysID = grBuilding.getUniqueValue();

                } else {
                    var grNewBuilding = new GlideRecord(FMConstants.Table.BUILDING);
                    grNewBuilding.initialize();
                    grNewBuilding.setValue('id', building);
                    grNewBuilding.setValue('name', building);
                    buildingSysID = grNewBuilding.insert();
                    
                    if(grNewBuilding.isActionAborted())
                        return FMFPOperationResult(false, "Building creation was aborted.");
                }

                grFloor.initialize();
                grFloor.setValue('id', floorID);

                // Changed because of kiosk dropdown value fetching 
                // grFloor.setValue('name', floor);
                grFloor.setValue('name', floorID);

                grFloor.setValue('building', buildingSysID);
                floorSysID = grFloor.insert();
                
                if(grFloor.isActionAborted())
                    return FMFPOperationResult(false, "Floor creation was aborted.");

                //update new values to the version record
                var versionNumber = floorID + ".000";

                grFloorVersion.setValue('record', floorSysID);
                grFloorVersion.setValue('name', floor + " - " + versionNumber);
                grFloorVersion.setValue('version', versionNumber);
                grFloorVersion.update();
                
                if(grFloorVersion.isActionAborted())
                    return FMFPOperationResult(false, "Version update was aborted.");

                //update the filename to match the floor ID
                var globalAutoCAD_Utils = new global.FM_AutoCAD_Utils();
                globalAutoCAD_Utils.renameAttachments(versionSysID, floorID);

            } else {
                floorSysID = grFloorVersion.getValue('record');
                grFloor.get(floorSysID);
                buildingSysID = grFloor.getValue('building');
            }
            

            return {
                'floor': floorSysID,
                'building': buildingSysID
            };
        }
    }
    
   /*
    * Function used to create a building manually from AutoCAD
    * @param buildingID {string} ID of the Building
    * @param buildingName {string} Name of the Building
    * @return FMFPOperationResult.result {string} Returns sys_id of the newly created Building
    */
    function createBuilding(buildingID, buildingName) {
        
        //Check if there is a building with the given ID
        var grBuildings = new GlideRecord(FMConstants.Table.BUILDING);
        grBuildings.addQuery("id", buildingID);
        grBuildings.query();
        
        if (grBuildings.next()){
            return new FMFPOperationResult(false,'A building record with the specified ID already exists.',undefined);
        }
        
        //Create new building
        var grBuilding = new GlideRecord(FMConstants.Table.BUILDING);
        grBuilding.initialize();
        grBuilding.id = buildingID;
        grBuilding.name = buildingName;
        grBuilding.insert();
        
        var building = {};
        building.Id = buildingID;
        building.Name = buildingName;
        building.Sys_Id = grBuilding.getUniqueValue();
        
        return new FMFPOperationResult(true,'New building created.', building);
    }
    
   /*
    * Function used to create floor manually from AutoCAD
    * @param floorID {string} ID of the Floor
    * @param floorName {string} Name of the Floor
    * @param floorLevel {integer} Number of the Floor level
    * @param buildingSysID {string} sys_id of the Building the Floor belongs to
    * @result FMFPOperationResult.result {string} Returns sys_id of the newly created Floor
    */
    function createFloor(floorID, floorName, floorLevel, buildingSysID) {
        
        //Check if there is a floor with the given ID
        var grFloors = new GlideRecord(FMConstants.Table.FLOOR);
        grFloors.addQuery("id", floorID);
        grFloors.query();
        
        if (grFloors.next())
            return new FMFPOperationResult(false,'A floor record with the specified ID already exists.',undefined);
        
        //Create new floor
        var grFloor = new GlideRecord(FMConstants.Table.FLOOR);
        grFloor.initialize();
        grFloor.id = floorID;
        grFloor.name = floorName;
        grFloor.level = floorLevel;
        grFloor.building = buildingSysID;
        grFloor.insert();
        
        var floor = {};
        floor.Id = floorID;
        floor.Name = floorName;
        floor.Sys_Id = grFloor.getUniqueValue();
        
        return new FMFPOperationResult(true,'New floor created.',floor);
    }
    
   /*
    * Retrieve location filtering visibility properties
    * @result FMFPOperationResult.result {JSON} returns the Filters options for Country, State, City
    */
    function getLocationFilteringOptions() {
        var json = {
            autocad_show_country_filter: gs.getProperty(FMConstants.Property.AUTOCAD_SHOW_COUNTRY_FILTER),
            autocad_show_state_filter: gs.getProperty(FMConstants.Property.AUTOCAD_SHOW_STATE_FILTER),
            autocad_show_city_filter: gs.getProperty(FMConstants.Property.AUTOCAD_SHOW_CITY_FILTER)
        };
        
        return new FMFPOperationResult(true,'Operation successful.',json);
    }
        
   /*
    * Data retrieve depending on facility
    * @param fmClass {string} name of the facility to query it's table
    * @param sys_id {string} sys_id of the facility
    * @result FMFPOperationResult.result {JSON} returns a JSON with facility info
    */
    function _getData(fmClass, sys_id) {
        var facilityActiveVersionInfo;
        var json = [];
        var gr = new GlideRecord("x_lsmcb_fm_" + fmClass);
        if (sys_id) {

            if (fmClass === "room") {
                gr.addQuery("floor", sys_id);
            }
            if (fmClass === "floor") {
                gr.addQuery("building", sys_id);
            }
        }
        gr.query();
        while (gr.next()) {
            facilityActiveVersionInfo = getFacilityActiveVersionInfo();
            if (facilityActiveVersionInfo.success){
                facility = {
                    id: gr.getValue("id"),
                    name: gr.getValue("name"),
                    sys_id: gr.getValue("sys_id"),
                    checkout: facilityActiveVersionInfo.result
                };

            } else {
                facility = {
                    id: gr.getValue("id"),
                    name: gr.getValue("name"),
                    sys_id: gr.getValue("sys_id"),
                    checkout: {}
                };
            }

            //Get buildings locations
            if (fmClass === "building") {
                facility.state = gr.getValue("state");
                facility.city = gr.getValue("city");
                //_getLocation(gr.parent_location,facility);
            }
            else if (fmClass === "floor") {
                var jsonVerify = FMFPVersionUtils().verifyFloor(gr.getUniqueValue());
                gs.info(JSON.stringify(jsonVerify));
                facility.read = jsonVerify.read;
                facility.write = jsonVerify.write;
                facility.create = jsonVerify.create;
            }
            json.push(facility);
        }
        return new FMFPOperationResult(true,'Operation successful.',json);
    }
            
   /*
    * Retrieve building location
    * @param location {GlideRecord} Record of the Location
    * @param building {JSON} Contains properties with info regarding a Building
    * @result {JSON} containing the Building info and it's location
    */
    function _getLocation(location, building) {
        if(!location){
            return building;
        }

        //If the building fields are not filled, fill them with the location fields
        if(!building.country && location.country){
            building.country = location.country.toString();
        }
        if(!building.state && location.state){
            building.state = location.state.toString();
        }
        if(!building.city && location.city){
            building.city = location.city.toString();
        }

        //State field is not required
        if((building.country && building.city) || !location.parent){
            return;
        }

        //If there are empty building fields rerun the function using the parent location
        _getLocation(location.parent, building);
    }


   /*
    * Retrieve sys_id of DWG attachment depending on version
    * @param version_sys_id {string} sys_id of the Version
    * @result FMFPOperationResult.result {string} sys_id of the DWG attachment
    */
    function _getVersionDWG(version_sys_id) {
        var grAttachment = new GlideRecord(FMConstants.Table.ATTACHMENT);
        grAttachment.addQuery("table_sys_id", version_sys_id);
        grAttachment.addQuery("content_type", "image/vnd.dwg");
        grAttachment.orderByDesc('sys_updated_on');
        grAttachment.setLimit(1);
        grAttachment.query();
        if (grAttachment.next())
            return new FMFPOperationResult(true,'Operation successful.',grAttachment.getValue("sys_id"));
        return new FMFPOperationResult(false,'Operation unsuccessful.',undefined);
    }

    return {
        'getBuildings':getBuildings,
        'getFacilityActiveVersionInfo':getFacilityActiveVersionInfo,
        'getFloorDWG':getFloorDWG,
        'getFloors':getFloors,
        'getRooms':getRooms,
        'getFacilityDetails':getFacilityDetails,
        'generateFacilities': generateFacilities,
        'createBuilding':createBuilding,
        'createFloor':createFloor,
        'getLocationFilteringOptions':getLocationFilteringOptions
    };
};